package com.fulu.game.bi.service.impl.market;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.fulu.game.bi.common.exception.BizException;
import com.fulu.game.bi.entity.enums.OsEnum;
import com.fulu.game.bi.entity.enums.QueryTypeStatusEnum;
import com.fulu.game.bi.entity.po.channel.Label;
import com.fulu.game.bi.entity.po.channel.RegistSource;
import com.fulu.game.bi.entity.vo.market.CommonlyDisplayVO;
import com.fulu.game.bi.entity.vo.market.CommonlyQueryVO;
import com.fulu.game.bi.mysql.bi.channel.LabelGroupDao;
import com.fulu.game.bi.mysql.bi.channel.RegisterSourceGroupDao;
import com.fulu.game.bi.mysql.playadmin.channel.LabelDao;
import com.fulu.game.bi.mysql.playadmin.channel.RegistSourceDao;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommonlyStatService {

    @Autowired
    private RegisterSourceGroupDao registerSourceGroupDao;

    @Autowired
    private RegistSourceDao registSourceDao;

    @Autowired
    private LabelGroupDao labelGroupDao;

    @Autowired
    private LabelDao labelDao;

    public List getIf(Boolean condition, Supplier<List> var2) {
        if (condition) {
            return var2.get();
        }
        return Collections.emptyList();
    }

    public List getIfEmpty(Supplier<List> var1, Supplier<List> var2) {
        final List expectList = var1.get();
        if (CollectionUtil.isNotEmpty(expectList)) {
            return expectList;
        }
        return var2.get();
    }

    public List list(CommonlyQueryVO vo, Map<Integer, String> tableNameMap, CommonlyFunction fun) {
        if (Objects.isNull(vo.getQueryType())) {
            throw new BizException("查询类型不能为空");
        }

        offsetDay(vo);

        // 封装注册来源platform
        final Supplier<List> getByGroupId = () -> Optional.ofNullable(vo.getRegisterSourceGroupId())
                .map((groupId) -> registerSourceGroupDao.listItem(groupId))
                .orElse(Collections.emptyList());
        final List<Integer> realSourceIdList = getIfEmpty(vo::getRegisterSourceIdList, getByGroupId);

        if (CollectionUtils.isEmpty(realSourceIdList) && Objects.nonNull(vo.getRegisterSourceGroupId())) {
            log.warn("渠道分组{}下不存在渠道", vo.getRegisterSourceGroupId());
            return Collections.emptyList();
        }

        final List<RegistSource> realSourceList = getIf(CollectionUtils.isNotEmpty(realSourceIdList), () -> registSourceDao.findByIds(realSourceIdList));

        final List<Integer> realSourcePlatformList = realSourceList.stream().map(RegistSource::getPlatform).collect(Collectors.toList());

        vo.setRealSourcePlatformList(realSourcePlatformList);

        final Map<Integer, String> sourceMap = realSourceList.stream().collect(Collectors.toMap(RegistSource::getPlatform, RegistSource::getName));
        String sourceGroupName = Optional.ofNullable(vo.getRegisterSourceGroupId()).map(id -> registerSourceGroupDao.findNameById(id)).orElse("/");

        // 封装标签id
        final Supplier<List> getLabelIdByGroupId = () -> Optional.ofNullable(vo.getLabelGroupId())
                .map((groupId) -> labelGroupDao.listItem(groupId))
                .orElse(Collections.emptyList());
        final List<Integer> labelIdList = getIfEmpty(vo::getLabelIdList, getLabelIdByGroupId);

        if (CollectionUtils.isEmpty(labelIdList) && Objects.nonNull(vo.getLabelGroupId())) {
            log.warn("标签分组{}下不存在标签", vo.getLabelGroupId());
            return Collections.emptyList();
        }

        vo.setRealLabelIdList(labelIdList);

        final List<Label> labelList = getIf(CollectionUtil.isNotEmpty(labelIdList), () -> labelDao.findByIds(labelIdList));
        final Map<Integer, String> labelMap = labelList.stream().collect(Collectors.toMap(Label::getId, Label::getName));
        String labelGroupName = Optional.ofNullable(vo.getLabelGroupId()).map(id -> labelGroupDao.findNameById(id)).orElse("/");
        // 注册系统类型
        final String osTypeName = Optional.ofNullable(vo.getRegisterType()).map(type -> OsEnum.parse(type).getMsg()).orElse("/");
        // 设置查询表名
        vo.setTableName(tableNameMap.get(vo.getQueryType()));

        final List<CommonlyDisplayVO> list = fun.convert();

        return list.stream()
                .peek(v -> v.setRegisterTypeName(osTypeName))
                .peek(v -> v.setLabelName(Optional.ofNullable(labelMap.get(v.getLabelId())).orElse("/")))
                .peek(v -> v.setSourceName(Optional.ofNullable(sourceMap.get(v.getSourceId())).orElse("/")))
                .peek(v -> v.setSourceGroupName(sourceGroupName))
                .peek(v -> v.setLabelGroupName(labelGroupName))
                .peek(v -> v.setBeginStatDay(v.getStatDate()))
                .peek(v -> v.setEndStatDay(getEndDateStr(vo, v.getStatDate())))
                .peek(v -> v.setSourceId(v.getSourceId() == null ? 0 : v.getSourceId()))
                .sorted(Comparator.comparing(CommonlyDisplayVO::getStatDate).reversed().thenComparing(CommonlyDisplayVO::getSourceId))
                .collect(Collectors.toList());
    }

    protected void offsetDay(CommonlyQueryVO vo) {
        if (QueryTypeStatusEnum.DAY.getType().equals(vo.getQueryType())) {
            Date statTimeEnd = vo.getStatTimeEnd();
            DateTime yestDay = DateUtil.offsetDay(new Date(), -1);
            if (Objects.isNull(statTimeEnd) || statTimeEnd.compareTo(yestDay) > 0) {
                vo.setStatTimeEnd(yestDay);
            }
        }
    }

    private String getEndDateStr(CommonlyQueryVO vo, String statDate) {
        if (QueryTypeStatusEnum.WEEK.getType().equals(vo.getQueryType())) {
            DateTime startTime = DateUtil.parse(statDate);
            DateTime endDateTime = DateUtil.offsetDay(startTime, 6);

            return DateUtil.format(endDateTime, "yyyy-MM-dd");
        } else {
            return statDate;
        }
    }

}
